import Taro from '@tarojs/taro'

// 错误类型枚举
export const ERROR_TYPES = {
  NETWORK: 'NETWORK',
  BUSINESS: 'BUSINESS',
  VALIDATION: 'VALIDATION',
  PERMISSION: 'PERMISSION',
  SYSTEM: 'SYSTEM'
}

// 错误级别枚举
export const ERROR_LEVELS = {
  LOW: 'LOW',
  MEDIUM: 'MEDIUM',
  HIGH: 'HIGH',
  CRITICAL: 'CRITICAL'
}

// 错误处理器类
class ErrorHandler {
  constructor() {
    this.errorLog = []
    this.maxLogSize = 100
    this.reportUrl = '/api/error/report'
  }

  // 处理错误
  handle(error, context = {}) {
    const errorInfo = this.parseError(error, context)
    this.logError(errorInfo)
    this.showError(errorInfo)
    
    // 严重错误需要上报
    if (errorInfo.level === ERROR_LEVELS.HIGH || errorInfo.level === ERROR_LEVELS.CRITICAL) {
      this.reportError(errorInfo)
    }

    return errorInfo
  }

  // 解析错误信息
  parseError(error, context) {
    const timestamp = new Date().toISOString()
    const errorInfo = {
      timestamp,
      message: '未知错误',
      type: ERROR_TYPES.SYSTEM,
      level: ERROR_LEVELS.MEDIUM,
      stack: error.stack,
      context,
      ...this.getSystemInfo()
    }

    // 根据错误类型解析
    if (error.statusCode) {
      // HTTP 错误
      errorInfo.type = ERROR_TYPES.NETWORK
      errorInfo.code = error.statusCode
      errorInfo.message = this.getHttpErrorMessage(error.statusCode)
      errorInfo.level = error.statusCode >= 500 ? ERROR_LEVELS.HIGH : ERROR_LEVELS.MEDIUM
    } else if (error.code) {
      // 业务错误
      errorInfo.type = ERROR_TYPES.BUSINESS
      errorInfo.code = error.code
      errorInfo.message = error.message || '业务处理失败'
      errorInfo.level = this.getBusinessErrorLevel(error.code)
    } else if (error.errMsg) {
      // 小程序API错误
      errorInfo.type = ERROR_TYPES.SYSTEM
      errorInfo.message = error.errMsg
      errorInfo.level = ERROR_LEVELS.LOW
    } else if (error.message) {
      // 普通错误
      errorInfo.message = error.message
    }

    return errorInfo
  }

  // 获取HTTP错误信息
  getHttpErrorMessage(statusCode) {
    const messages = {
      400: '请求参数错误',
      401: '未授权访问',
      403: '禁止访问',
      404: '资源不存在',
      408: '请求超时',
      429: '请求过于频繁',
      500: '服务器内部错误',
      502: '网关错误',
      503: '服务不可用',
      504: '网关超时'
    }
    return messages[statusCode] || `HTTP错误: ${statusCode}`
  }

  // 获取业务错误级别
  getBusinessErrorLevel(code) {
    const criticalCodes = [1001, 1002] // 登录相关
    const highCodes = [3001, 3002] // 支付相关
    
    if (criticalCodes.includes(code)) return ERROR_LEVELS.CRITICAL
    if (highCodes.includes(code)) return ERROR_LEVELS.HIGH
    return ERROR_LEVELS.MEDIUM
  }

  // 获取系统信息
  getSystemInfo() {
    try {
      const systemInfo = Taro.getSystemInfoSync()
      return {
        platform: systemInfo.platform,
        version: systemInfo.version,
        model: systemInfo.model,
        pixelRatio: systemInfo.pixelRatio,
        windowWidth: systemInfo.windowWidth,
        windowHeight: systemInfo.windowHeight
      }
    } catch (e) {
      return {}
    }
  }

  // 记录错误日志
  logError(errorInfo) {
    console.error('🚨 错误详情:', errorInfo)
    
    this.errorLog.unshift(errorInfo)
    
    // 限制日志大小
    if (this.errorLog.length > this.maxLogSize) {
      this.errorLog = this.errorLog.slice(0, this.maxLogSize)
    }

    // 存储到本地
    try {
      Taro.setStorageSync('errorLog', this.errorLog.slice(0, 10))
    } catch (e) {
      console.warn('保存错误日志失败:', e)
    }
  }

  // 显示错误提示
  showError(errorInfo) {
    // 根据错误级别决定显示方式
    switch (errorInfo.level) {
      case ERROR_LEVELS.CRITICAL:
        Taro.showModal({
          title: '系统错误',
          content: errorInfo.message,
          showCancel: false,
          confirmText: '重新加载',
          success: () => {
            // 重新加载页面或重启应用
            Taro.reLaunch({ url: '/pages/index/index' })
          }
        })
        break
        
      case ERROR_LEVELS.HIGH:
        Taro.showModal({
          title: '操作失败',
          content: errorInfo.message,
          showCancel: true,
          cancelText: '取消',
          confirmText: '重试'
        })
        break
        
      case ERROR_LEVELS.MEDIUM:
        Taro.showToast({
          title: errorInfo.message,
          icon: 'none',
          duration: 2000
        })
        break
        
      case ERROR_LEVELS.LOW:
        // 低级别错误只在控制台输出，不打扰用户
        console.warn('低级别错误:', errorInfo.message)
        break
    }
  }

  // 上报错误
  async reportError(errorInfo) {
    try {
      // 只在生产环境上报
      if (process.env.NODE_ENV !== 'production') {
        console.log('开发环境，跳过错误上报:', errorInfo)
        return
      }

      await Taro.request({
        url: this.reportUrl,
        method: 'POST',
        data: {
          ...errorInfo,
          userAgent: navigator.userAgent,
          url: window.location?.href || 'miniprogram'
        }
      })
    } catch (e) {
      console.warn('错误上报失败:', e)
    }
  }

  // 获取错误日志
  getErrorLog() {
    return this.errorLog
  }

  // 清空错误日志
  clearErrorLog() {
    this.errorLog = []
    try {
      Taro.removeStorageSync('errorLog')
    } catch (e) {
      console.warn('清空错误日志失败:', e)
    }
  }

  // 设置错误上报地址
  setReportUrl(url) {
    this.reportUrl = url
  }
}

// 创建全局错误处理器实例
const errorHandler = new ErrorHandler()

// 全局错误监听
if (typeof window !== 'undefined') {
  // H5环境
  window.addEventListener('error', (event) => {
    errorHandler.handle(event.error, {
      type: 'global',
      filename: event.filename,
      lineno: event.lineno,
      colno: event.colno
    })
  })

  window.addEventListener('unhandledrejection', (event) => {
    errorHandler.handle(event.reason, {
      type: 'promise'
    })
  })
}

export default errorHandler